The development of the EDVAC computer system of 1948 is often cited as the beginning of the computer era. Since that time, computer systems have evolved into extremely sophisticated devices, and computer systems may be found in many different settings. Computer systems typically include a combination of hardware, such as semiconductors and circuit boards, and software, also known as computer programs. As advances in semiconductor processing and computer architecture push the performance of the computer hardware higher, more sophisticated and complex computer software has evolved to take advantage of the higher performance of the hardware, resulting in computer systems today that are much more powerful than just a few years ago.
As the sophistication and complexity of computer software increase, the more difficult the software is to debug. Bugs are problems, faults, or errors in a computer program. Locating, analyzing, and correcting suspected faults in a computer program is a process known as “debugging.” Typically, a programmer uses another computer program commonly known as a “debugger” to debug the program under development.
Conventional debuggers typically support two primary operations to assist a computer programmer. A first operation supported by conventional debuggers is a “step” function, which permits a computer programmer to process instructions (also known as “statements”) in a computer program one-by-one and see the results upon completion of each instruction. While the step operation provides a programmer with a large amount of information about a program during its execution, stepping through hundreds or thousands of program instructions can be extremely tedious and time consuming and may require the programmer to step through many program instructions that are known to be error-free before a set of instructions to be analyzed is finally executed.
To address this difficulty, a second operation supported by conventional debuggers is a breakpoint operation, which permits a computer programmer to identify with a breakpoint a precise instruction for which it is desired to halt execution of a computer program during execution. As a result, when a computer program is executed by a debugger, the program executes in a normal fashion until the breakpoint is reached. The debugger then stops execution of the program and displays the results of the program and/or the state of the computer system to the programmer for analysis, typically via a debugger user interface.
Typically, step operations and breakpoints are used together to simplify the debugging process. Specifically, a common debugging operation is to set a breakpoint at the beginning of a desired set of instructions to be analyzed and then begin executing the program. Once the breakpoint is reached, the debugger halts the program, and the programmer then steps through the desired set of instructions line-by-line using the step operation. Consequently, a programmer is able to more quickly isolate and analyze a particular set of instructions without needing to step through irrelevant portions of a computer program.
But, sometimes the user does not know the address of the instruction to be analyzed. Instead, the user knows the name of a variable or an address of a storage location used by the program that the program may eventually modify, and the user would like the debugger to stop the program when the program modifies the contents at that storage location or in that variable. To address this need, some debuggers have a special breakpoint function, called an address watch breakpoint (AWB). When the program being debugged modifies the contents of the storage location specified by the address watch breakpoint, the debugger stops the program at the instruction that is modifying the storage. Thus, an address watch breakpoint instruction is a load or store instruction accessing a location within a memory page being monitored as an address watch breakpoint.
One of the problems with address watch breakpoints is when the user attempts to set an address watch breakpoint to a variable referenced by a basing pointer or pointer expression, which is not yet set (the basing pointer does not yet contain a valid address). Current debuggers typically use hardware watch capabilities to implement the address watch breakpoint, which require the debuggers to resolve the pointer expression to be watched to obtain a single address to watch. If the basing pointer is not yet set, the expression cannot be resolved, and the single address cannot be obtained.
In an attempt to work around this problem, users sometimes try to run the program being debugged until the basing pointer is set and then set the address watch breakpoint. Unfortunately, determining when a basing pointer has been set is no easy task. The user must make an initial guess where the basing pointer might be set, run the program for a time, perhaps stepping or setting breakpoints near where the pointer might be set, and then manually check to see if the pointer is set. If the pointer is not yet set, then the user must try again until the pointer is set. Further, if the user has allowed the program to run too far, the user must start the process over again with some different breakpoints and/or number of steps. Even worse, finally finding a location in the program where the basing pointer is set does not necessarily end the difficulty because timing issues can cause further complications. Timing problems caused by the delay in setup (hitting a breakpoint, then setting the watch) may cause the address watch breakpoint to not fire in the same way compared to the normal operating environment where the program runs without the breakpoint. Timing issues are particularly troublesome when the program has multiple threads or interacts with other programs, tasks, or jobs running concurrently. Thus, the timing issues may cause the error or bug under investigation to be difficult to reproduce when address watch breakpoints are used with basing pointers.
Hence, without a better way to handle address watch breakpoints directed to variables that are referenced via basing pointers, developers will continue to experience delay, frustration, and difficulty when debugging programs.